Model¶

In [4]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import poisson

from mesa import Agent, Model
from mesa.time import RandomActivation
from mesa.space import MultiGrid
from mesa.batchrunner import batch_run
from mesa.datacollection import DataCollector

import solara
from matplotlib.figure import Figure
import ipywidgets as widgets
from IPython.display import display

%matplotlib inline



class StudentAgent(Agent):
    """A student agent with attributes and behaviors."""   
    def __init__(self, unique_id, model, efficiency, credits):
        super().__init__(unique_id, model)
        self.efficiency = efficiency #general predictor of completing coursework on time
        self.credits = credits 
        self.credits_left = self.model.program_credits_required 
        self.financial_aid_status = False
        self.is_working = False
        self.graduated = False
        self.dropped = False
        if self.credits >= self.model.min_credits:
            self.financial_aid()
        self.peer_influence_impact = 0
        self.enrollment_year = 1
      
    #each step is one week.  15 weeks = 1 semester.    
    def step(self):
        """What happens to a student agent each week."""
        if self.graduated:
            return
        self.apply_first_year_rules()
        if self.dropped:
            return
        
        self.dropout() #chance to drop if working and low efficiency
        
        if self.efficiency < self.model.min_efficiency: # attempt to find support each week if struggling
            
            chance_to_meet = np.random.random()
            if chance_to_meet< 0.3:
                self.professor_interaction()
            if chance_to_meet> 0.3 and chance_to_meet < 0.6:
                self.seek_support()
       
        #noise / adverse events
        if np.random.random() < 0.03:
            self.efficiency -= np.random.uniform(self.model.low_impact, self.model.high_impact)
            

        if np.random.random() > 0.93: #random chance to get positive feedback from professors on assignments
            self.professor_interaction()

    #testing different policies
    def apply_first_year_rules(self):
        return 
        """Policy for first-year students at high risk."""
        #if self.enrollment_year < 3 and self.efficiency < self.model.min_efficiency:
            #self.credits = min(self.credits, 9)  # Limit to 9 credits
            #self.financial_aid_status = True  # Grant financial aid
        
        
                
    def end_of_semester_update(self):
    
        """procedures at the end of each semester"""
        if self.credits_left > 0:
            # Attempt to pass courses based on current efficiency
            for _ in range(self.credits):  
                if np.random.random() < self.efficiency:  
                    self.credits_left -= 1  # Successfully passed a course
                    #self.efficiency += np.random.uniform(self.model.low_impact, self.model.high_impact) #boost for passing
                    #self.efficiency = min(max(self.efficiency, 0), 1)
                else:
                    #self.efficiency -= np.random.uniform(self.model.low_impact, self.model.high_impact) #loss of motivation for failing
                    self.efficiency = min(max(self.efficiency, 0), 1)
                    #this might be creating a rich-get-richer / poor-get-poorer effect.
        
        if self.credits_left <= 0:  # Check if all required credits are completed
            self.credits_left = 0
            self.graduated = True
            self.model.num_graduates +=1
            return  # Stop processing if all credits are completed
        
        #assumption: do too many credits decrease efficiency if working?
        if self.credits > 16 and self.is_working:
            self.efficiency -= np.random.random()*self.model.low_impact
            self.efficiency = min(max(self.efficiency, 0), 1)
        
        #award financial aid to those at required credit load
        if self.credits >= self.model.min_credits:
            self.financial_aid()        
        
        #assumption: full time student and working decreases effectiveness 
        if self.credits > 11 and self.is_working:
            self.efficiency -= np.random.uniform(self.model.low_impact, self.model.high_impact)
            self.efficiency = min(max(self.efficiency, 0), 1)
        
        #reduce credits if low efficiency and high credits.
        if self.efficiency < self.model.min_efficiency:
            if self.credits > self.model.min_credits:
                self.credits = max (self.credits - 4, self.model.min_credits)
        
        """#possibly take on more classes if part time and doing well?
        if self.efficiency > self.model.min_efficiency:
            if self.credits < self.model.min_credits:
                elected_credits = np.random.randint(0,3)
                self.credits += elected_credits
                """
                
        
    def dropout(self):
        if self.efficiency < 0.3 and self.is_working:
            self.model.dropped += 1
            self.dropped = True
        else: 
            if self.efficiency < 0.3 and np.random.random() < 0.5:
                self.model.dropped += 1
                self.dropped = True 

    def professor_interaction(self):
        if np.random.random() < self.model.college_efficiency: 
            self.efficiency += np.random.uniform(self.model.low_impact,self.model.high_impact) #strong predictor from data
            self.efficiency = min(max(self.efficiency, 0), 1)
            
    def financial_aid(self):
        increase = np.random.uniform(self.model.low_impact, self.model.high_impact)
        #receive award once
        if self.financial_aid_status:
            return
        else: 
            if np.random.random() < self.model.college_efficiency:
                self.efficiency = min(self.efficiency + increase, 1) #clamp to under 100%
                self.financial_aid_status = True
            
    def peer_influence(self):
        #cluster into groups (class sections)
        #find average efficiency of the group
        #move toward the mean from individual eff
        if self.pos is None:
            return
        neighbors = self.model.grid.get_neighbors(self.pos, moore=True, include_center=False, radius=3)
        if not neighbors:  
            return
        
        avg_efficiency = np.mean([neighbor.efficiency for neighbor in neighbors])
        
        #move the agent's efficiency toward the group's average
        self.peer_influence_impact = (avg_efficiency - self.efficiency)
        self.efficiency += self.peer_influence_impact*0.5
        self.efficiency = min(max(self.efficiency, 0), 1)  
        
    def seek_support(self):
        #interaction with support services can impact efficiency.  Depends on college efficiency to supply adequate support.
        if np.random.random() < self.model.college_efficiency:
            increase = np.random.uniform(-self.model.low_impact, self.model.high_impact) #small chance for confusion or discouragement
            self.efficiency = min(self.efficiency + increase, 1) 

class CollegeModel(Model):
    """A model with agents and policies."""    
    def __init__(self, N, width, height, min_efficiency=0.65, min_credits=12, 
                 program_credits_required=64, low_impact=0.01, high_impact=0.08, college_efficiency = 0.7):
        super().__init__()
        self.grid = MultiGrid(width, height, True)
        self.running = True #needed for batch runs
        self.num_agents = N
        self.min_efficiency = min_efficiency
        self.min_credits = min_credits
        self.program_credits_required = program_credits_required
        self.low_impact = low_impact
        self.high_impact = high_impact
        self.college_efficiency = college_efficiency
        self.recruitment = np.random.randint(50,150) 
        self.num_graduates = 0
        self.dropped = 0

        self.schedule = RandomActivation(self)
        self.current_week = 1
       
        #create distribution for efficiencies
        std_dev = 0.1
        mean_eff=self.min_efficiency + std_dev
        
        efficiency_values = np.random.normal(mean_eff, std_dev, self.num_agents)
        efficiency_values = np.clip(efficiency_values,0,1)
        
        #create distribution for credits taken
        mean_credits = 12
        std_credits = 3
        credits_values = np.random.normal(mean_credits, std_credits, self.num_agents)
        credits_values = np.round(credits_values)

        
        
        # Create agents
        for i in range(self.num_agents):
            efficiency = efficiency_values[i]
            credits = int(credits_values[i])
            a = StudentAgent(i, self, efficiency, credits)
            #2/3 of community college students work 20 or more hours.
            a.is_working = np.random.random() < 0.67 
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))
            
            
            self.schedule.add(a)
  
        # Data collector
        self.datacollector = DataCollector(
            agent_reporters={"Efficiency": "efficiency", "Fin Aid Status": "financial_aid_status", "Credits": "credits", "Credits Remain": "credits_left"},
            model_reporters={"AveragePeerInfluence": self.average_peer_influence, "AverageEfficiency": self.average_efficiency, "WorkingEfficiency": self.average_efficiency_working, "AverageCredits": self.average_credits, "AvgCredsLeft": self.avg_credits_left, "Graduates": self.graduates, "Dropped":self.dropouts, "EfficiencyWithAid": self.average_efficiency_with_aid },
        )  # Add more metrics 
    
    def add_new_students(self, num_new_students):
        """Add new students to the model."""

        std_dev = 0.1
        mean_eff = self.min_efficiency + std_dev

        efficiency_values = np.random.normal(mean_eff, std_dev, num_new_students)
        efficiency_values = np.clip(efficiency_values, 0, 1)

        mean_credits = 12
        std_credits = 3
        credits_values = np.random.normal(mean_credits, std_credits, num_new_students)
        credits_values = np.round(credits_values)

        for i in range(num_new_students):
            efficiency = efficiency_values[i]
            credits = int(credits_values[i])
            new_id = self.num_agents  # New ID for the new student

            a = StudentAgent(new_id, self, efficiency, credits)
            a.is_working = np.random.random() < 0.67  # 2/3 of community college students work 20 or more hours.

            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)

            self.grid.place_agent(a, (x, y))
            self.schedule.add(a)
            self.num_agents += 1

    def remove_graduated_students(self):
        """Remove graduated students from the model."""
        graduated_agents = [agent for agent in self.schedule.agents if agent.graduated]

        for agent in graduated_agents:
            self.schedule.remove(agent)
            self.grid.remove_agent(agent)
    def remove_dropped_students(self):
        """Remove dropped students from the model."""
        dropped_agents = [agent for agent in self.schedule.agents if agent.dropped]
        
        for agent in dropped_agents:
            self.schedule.remove(agent)
            self.grid.remove_agent(agent)
            self.dropped += 1
    
    def early_intervention(self):
        for student in self.schedule.agents:
            if student.efficiency < 0.4 and np.random.random() < self.college_efficiency:  # Early alert threshold with chance to fail
                
                student.seek_support()  # Direct them to support services
                student.professor_interaction()
               
    
    def average_credits(self):
        agent_credits = [agent.credits for agent in self.schedule.agents]
        return sum(agent_credits) / len(agent_credits)
    
    def financial_aid_utilization(self):
        aid_recipients = len([agent for agent in self.schedule.agents if agent.financial_aid_status])
        return aid_recipients / self.num_agents

    #Data Collection Methods    
    def graduates(self):
        return self.num_graduates
    
    def dropouts(self):
        return self.dropped
    
    def average_efficiency_with_aid(self):
        aid_students = [agent.efficiency for agent in self.schedule.agents if agent.financial_aid_status]
        return sum(aid_students) / len(aid_students) if aid_students else 0  # Avoid division by zero
    
    def average_peer_influence(self):
        peer_changes = [agent.peer_influence_impact for agent in self.schedule.agents]
        return sum(peer_changes) / len(peer_changes) if peer_changes else 0

    def avg_credits_left(self):
        agent_credits_left = [agent.credits_left for agent in self.schedule.agents]
        return sum(agent_credits_left) / len(agent_credits_left)
  
    def average_efficiency(self):
        agent_efficiencies = [agent.efficiency for agent in self.schedule.agents]
        return sum(agent_efficiencies) / len(agent_efficiencies)
        
    def average_efficiency_working(self):
        working_efficiencies = [agent.efficiency for agent in self.schedule.agents if agent.is_working]
        if not working_efficiencies:
            return 0
        return sum(working_efficiencies) / len(working_efficiencies)
    
    def end_of_semester_logic(self):        
        self.remove_graduated_students()  # Remove graduated students
        self.add_new_students(self.recruitment)
        self.early_intervention()
        for agent in self.schedule.agents:
            if agent.graduated:
                continue
            agent.enrollment_year +=1
            agent.end_of_semester_update()
            agent.peer_influence()
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.move_agent(agent, (x, y))

    #Step model forward one week
    def step(self):
        self.schedule.step()
        if self.current_week%5==0:
            self.early_intervention()
        if self.current_week == 15:
            self.end_of_semester_logic()
            self.current_week = 1  # Reset for next semester
        else:
            self.current_week += 1
        self.remove_dropped_students()
        self.datacollector.collect(self)

Batch Runs¶

Varying Min Efficiencies¶

In [5]:
model_cls = CollegeModel

parameters = {
    "N": [250],  # Number of agents in the model
    "width": [25],
    "height": [25],
    "min_efficiency": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]  # Exploring different efficiencies
}
number_processes = 1  # Use 1 processes, or set to None for all CPUs
data_collection_period = 1  # Collect data every week
max_steps = 200  # Run up to 180 weeks per model
display_progress = True  # Show progress
iterations = 3  # Run each parameter combination 3 times


results = batch_run(
    model_cls=CollegeModel,
    parameters=parameters,
    number_processes=number_processes,
    iterations=iterations,
    data_collection_period=data_collection_period,
    max_steps=max_steps,
    display_progress=display_progress,
)

results_df = pd.DataFrame(results)
#print(results_df.head())
#display(results_df)
#results_df.to_excel('results.xlsx', sheet_name='Simulation Results', index=False)
  0%|          | 0/30 [00:00<?, ?it/s]
In [6]:
import matplotlib.pyplot as plt

#plots to compare Overall Eff, Of those working, and of those with Fin Aid
grouped_df = results_df.groupby(["min_efficiency", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
    WorkingEfficiency=("WorkingEfficiency", "mean"),
    EfficiencyWithAid=("EfficiencyWithAid", "mean"),
).reset_index()


efficiencies = grouped_df["min_efficiency"].unique()

fig, axes = plt.subplots(nrows=len(efficiencies), ncols=1, figsize=(10, 6 * len(efficiencies)))

for idx, efficiency in enumerate(efficiencies):
    df_eff = grouped_df[grouped_df["min_efficiency"] == efficiency]

    axes[idx].plot(df_eff["Step"], df_eff["Efficiency"], label="Efficiency")
    axes[idx].plot(df_eff["Step"], df_eff["WorkingEfficiency"], label="WorkingEfficiency")
    axes[idx].plot(df_eff["Step"], df_eff["EfficiencyWithAid"], label="EfficiencyWithAid")
    #axes[idx].plot(df_eff["Step"], df_eff["PeerInfluence"], label="PeerInfluence")

    axes[idx].set_title(f"Efficiency: {efficiency}")
    axes[idx].set_xlabel("Step")
    axes[idx].set_ylabel("Efficiency")
    axes[idx].legend()
    plt.grid()


plt.tight_layout()
plt.show()


#Tracking individual agents through time for more insight
iteration_df = results_df[results_df["iteration"] == 0]
target_agents = [95, 100, 105, 110, 115, 120]  
df_agents = iteration_df[iteration_df["AgentID"].isin(target_agents)]
grouped_agents = df_agents.groupby(["AgentID", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
    Credits_Remain=("Credits Remain","mean"),
).reset_index()

grouped_agents = df_agents.groupby(["AgentID", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
).reset_index()

plt.figure(figsize=(12, 8))

for agent_id in target_agents:
    df_agent = grouped_agents[grouped_agents["AgentID"] == agent_id]
    plt.plot(df_agent["Step"], df_agent["Efficiency"], label=f"Agent {agent_id}")

plt.title("Efficiencies of Selected Agents Over Time")
plt.xlabel("Step")
plt.ylabel("Efficiency")
plt.legend()

plt.grid()
plt.show()
No description has been provided for this image
No description has been provided for this image

Varying Credits for Financial Aid¶

In [7]:
model_cls = CollegeModel

parameters = {
    "N": [250],  # Number of agents in the model
    "width": [25],
    "height": [25],
    "min_efficiency":[0.65],
    "min_credits": [3, 4, 5, 6, 7, 8,9, 10, 11, 12, 13, 14, 15, 16]
}
number_processes = 1  # Use 1 processes, or set to None for all CPUs
data_collection_period = 1  # Collect data every week
max_steps = 200  # Run up to 180 weeks per model
display_progress = True  # Show progress
iterations = 3  # Run each parameter combination 3 times


results = batch_run(
    model_cls=CollegeModel,
    parameters=parameters,
    number_processes=number_processes,
    iterations=iterations,
    data_collection_period=data_collection_period,
    max_steps=max_steps,
    display_progress=display_progress,
)

results_df = pd.DataFrame(results)
print(results_df.head())
display(results_df)
#results_df.to_excel('results.xlsx', sheet_name='Simulation Results', index=False)
  0%|          | 0/42 [00:00<?, ?it/s]
   RunId  iteration  Step    N  width  height  min_efficiency  min_credits  \
0      0          0     0  250     25      25            0.65            3   
1      0          0     1  250     25      25            0.65            3   
2      0          0     1  250     25      25            0.65            3   
3      0          0     1  250     25      25            0.65            3   
4      0          0     1  250     25      25            0.65            3   

   AveragePeerInfluence  AverageEfficiency  ...  AverageCredits  AvgCredsLeft  \
0                   0.0           0.786010  ...          11.852          64.0   
1                   0.0           0.788178  ...          11.852          64.0   
2                   0.0           0.788178  ...          11.852          64.0   
3                   0.0           0.788178  ...          11.852          64.0   
4                   0.0           0.788178  ...          11.852          64.0   

   Graduates  Dropped  EfficiencyWithAid  AgentID  Efficiency  Fin Aid Status  \
0          0        0           0.805565      NaN         NaN             NaN   
1          0        0           0.806741    142.0    0.709348            True   
2          0        0           0.806741    173.0    0.768375            True   
3          0        0           0.806741    230.0    0.783945           False   
4          0        0           0.806741    196.0    0.720027           False   

  Credits  Credits Remain  
0     NaN             NaN  
1     8.0            64.0  
2     9.0            64.0  
3     2.0            64.0  
4     8.0            64.0  

[5 rows x 21 columns]
RunId iteration Step N width height min_efficiency min_credits AveragePeerInfluence AverageEfficiency ... AverageCredits AvgCredsLeft Graduates Dropped EfficiencyWithAid AgentID Efficiency Fin Aid Status Credits Credits Remain
0 0 0 0 250 25 25 0.65 3 0.000000 0.786010 ... 11.852000 64.000000 0 0 0.805565 NaN NaN NaN NaN NaN
1 0 0 1 250 25 25 0.65 3 0.000000 0.788178 ... 11.852000 64.000000 0 0 0.806741 142.0 0.709348 True 8.0 64.0
2 0 0 1 250 25 25 0.65 3 0.000000 0.788178 ... 11.852000 64.000000 0 0 0.806741 173.0 0.768375 True 9.0 64.0
3 0 0 1 250 25 25 0.65 3 0.000000 0.788178 ... 11.852000 64.000000 0 0 0.806741 230.0 0.783945 False 2.0 64.0
4 0 0 1 250 25 25 0.65 3 0.000000 0.788178 ... 11.852000 64.000000 0 0 0.806741 196.0 0.720027 False 8.0 64.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
5720266 41 2 200 250 25 25 0.65 16 0.008122 0.774060 ... 11.275097 26.055985 1057 0 0.767108 1458.0 0.820520 False 11.0 30.0
5720267 41 2 200 250 25 25 0.65 16 0.008122 0.774060 ... 11.275097 26.055985 1057 0 0.767108 1657.0 0.729751 False 12.0 36.0
5720268 41 2 200 250 25 25 0.65 16 0.008122 0.774060 ... 11.275097 26.055985 1057 0 0.767108 1325.0 0.780443 True 18.0 0.0
5720269 41 2 200 250 25 25 0.65 16 0.008122 0.774060 ... 11.275097 26.055985 1057 0 0.767108 692.0 0.747620 False 9.0 5.0
5720270 41 2 200 250 25 25 0.65 16 0.008122 0.774060 ... 11.275097 26.055985 1057 0 0.767108 1464.0 0.837398 False 8.0 37.0

5720271 rows × 21 columns

In [8]:
import matplotlib.pyplot as plt

#plots to compare Overall Eff, Of those working, and of those with Fin Aid
grouped_df = results_df.groupby(["min_credits", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
    WorkingEfficiency=("WorkingEfficiency", "mean"),
    EfficiencyWithAid=("EfficiencyWithAid", "mean"),
).reset_index()

credits = grouped_df["min_credits"].unique()

fig, axes = plt.subplots(nrows=len(credits), ncols=1, figsize=(10, 6 * len(credits)))

for idx, credits in enumerate(credits):
    df_eff = grouped_df[grouped_df["min_credits"] == credits]

    axes[idx].plot(df_eff["Step"], df_eff["Efficiency"], label="Efficiency")
    axes[idx].plot(df_eff["Step"], df_eff["WorkingEfficiency"], label="WorkingEfficiency")
    axes[idx].plot(df_eff["Step"], df_eff["EfficiencyWithAid"], label="EfficiencyWithAid")
    #axes[idx].plot(df_eff["Step"], df_eff["PeerInfluence"], label="PeerInfluence")

    axes[idx].set_title(f"Credits: {credits}")
    axes[idx].set_xlabel("Step")
    axes[idx].set_ylabel("Efficiency")
    axes[idx].legend()
    plt.grid()


plt.tight_layout()
plt.show()



#Tracking individual agents through time for more insight
iteration_df = results_df[results_df["iteration"] == 0]
target_agents = [95, 100, 105, 110, 115, 120]  
df_agents = iteration_df[iteration_df["AgentID"].isin(target_agents)]
grouped_agents = df_agents.groupby(["AgentID", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
    Credits_Remain=("Credits Remain","mean"),
).reset_index()

grouped_agents = df_agents.groupby(["AgentID", "Step"]).agg(
    Efficiency=("Efficiency", "mean"),
).reset_index()

plt.figure(figsize=(12, 8))

for agent_id in target_agents:
    df_agent = grouped_agents[grouped_agents["AgentID"] == agent_id]
    plt.plot(df_agent["Step"], df_agent["Efficiency"], label=f"Agent {agent_id}")

plt.title("Efficiencies of Selected Agents Over Time")
plt.xlabel("Step")
plt.ylabel("Efficiency")
plt.legend()

plt.grid()
plt.show()
No description has been provided for this image
No description has been provided for this image

Visualizer¶

In [10]:
from mesa.experimental import JupyterViz

def agent_portrayal(agent):
    size = 5
    color = "tab:blue"
    if agent.efficiency < agent.model.min_efficiency:
        size = 50
        color = "tab:red"
    return{"size":size, "color": color, "Shape":"rect"}

def make_histogram(model):
    fig = Figure()
    ax = fig.subplots()
    credits = [agent.credits for agent in model.schedule.agents]
    # Note: you have to use Matplotlib's OOP API instead of plt.hist
    # because plt.hist is not thread-safe.
    ax.hist(credits, bins=10)
    solara.FigureMatplotlib(fig)

def eff_histogram(model):
    agent_efficiencies = [agent.efficiency for agent in model.schedule.agents]
    plt.hist(agent_efficiencies, bins=10)
    plt.title("Agent Efficiencies Histogram")
    plt.xlabel("Efficiency")
    plt.ylabel("Count")
    plt.show()

def graduation_vs_dropout(model):
    plt.figure(figsize=(8, 5))
    graduates = model.graduates()
    dropouts = model.dropouts()
    plt.bar(["Graduates", "Dropouts"], [graduates, dropouts], color=["green", "red"])
    plt.title("Graduates vs. Dropouts")
    plt.ylabel("Number")
    plt.show()


model_params = {
    "N": {
        "type": "SliderInt",
        "value": 150,
        "label": "Number of Students:",
        "min": 10,
        "max": 500,
        "step": 5,
    },
    "width": 25,
    "height": 25,
    "min_efficiency": {
        "type": "SliderFloat",
        "value": 0.65,
        "label": "Minimum Efficiency:",
        "min": 0.0,
        "max": 1.0,
        "step": 0.05, 
    },
    "min_credits": {
        "type": "SliderInt",
        "value": 12,
        "label": "Minimum Credits for Financial Aid:",
        "min": 0,
        "max": 24,
        "step": 1, 
    },
    "program_credits_required": {
        "type": "SliderInt",
        "value": 64,
        "label": "Program Credits Required:",
        "min": 30,
        "max": 120,
        "step": 1,
    },
    "college_efficiency": {
        "type": "SliderFloat",
        "value": 0.5,
        "label": "College Efficiency:",
        "min": 0,
        "max": 1,
        "step": 0.01, 
    },
    "low_impact": {
        "type": "SliderFloat",
        "value": 0.01,
        "label": "Low Impact:",
        "min": 0.0,
        "max": 0.1,
        "step": 0.005,
    },
    "high_impact": {
        "type": "SliderFloat",
        "value": 0.05,
        "label": "High Impact:",
        "min": 0.05,
        "max": 0.25,
        "step": 0.01,
    },
}


page = JupyterViz(
    CollegeModel,
    model_params,
    measures=["AverageEfficiency","WorkingEfficiency", "AverageCredits", "AvgCredsLeft", "Graduates", make_histogram, "Dropped", graduation_vs_dropout, eff_histogram],
    name="FLCC Model",
    agent_portrayal=agent_portrayal,
    
)
page
C:\Users\maley\AppData\Local\Temp\ipykernel_27656\1925705021.py:35: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  plt.show()
C:\Users\maley\AppData\Local\Temp\ipykernel_27656\1925705021.py:26: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  plt.show()
C:\Users\maley\AppData\Local\Temp\ipykernel_27656\1925705021.py:35: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  plt.show()
C:\Users\maley\AppData\Local\Temp\ipykernel_27656\1925705021.py:26: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  plt.show()
Cannot show widget. You probably want to rerun the code cell above (Click in the code cell, and press Shift+Enter ⇧+↩).
In [ ]: